module mod_strings_ext

   use stdlib_string_type
   use stdlib_strings
contains

   pure function partition(self, sep) result(partitions)
      type(string_type), intent(in)            :: self            !< The string.
      character(len=*), intent(in), optional  :: sep             !< Separator.
      type(string_type)                               :: partitions(1:3) !< Partions: before the separator, the separator itsels and
      !< after the separator.
      character(len=:), allocatable                   :: sep_            !< Separator, default value.
      integer                                         :: c               !< Character counter.

      sep_ = " "; if (present(sep)) sep_ = sep

      partitions(1) = self
      partitions(2) = sep_
      partitions(3) = ''
      if (len(sep_) >= len(self)) return
      c = index(self, sep_)
      if (c > 0) then
         partitions(1) = slice(self, 1, c - 1)
         partitions(2) = slice(self, c, c + len(sep_) - 1)
         partitions(3) = slice(self, c + len(sep_))
      end if

   end function partition

   subroutine split(self, tokens, sep, max_tokens)
      type(string_type), intent(in)           :: self           !< The string.
      type(string_type), allocatable, intent(out)          :: tokens(:)      !< Tokens substring.
      character(len=*), intent(in), optional :: sep            !< Separator.
      integer, intent(in), optional :: max_tokens     !< Fix the maximum number of returned tokens.
      character(len=:), allocatable          :: sep_           !< Separator, default value.
      integer                                         :: No             !< Number of occurrences of sep.
      integer                                         :: t              !< Character counter.
      type(string_type)                               :: temporary      !< Temporary storage.
      type(string_type), allocatable                   :: temp_toks(:, :) !< Temporary tokens substring.

      sep_ = " "; if (present(sep)) sep_ = sep

      temporary = self
      No = count(temporary, sep_)

      if (No > 0) then
         if (present(max_tokens)) then
            if (max_tokens < No .and. max_tokens > 0) No = max_tokens
         end if
         allocate (temp_toks(3, No))
         temp_toks(:, 1) = partition(temporary, sep_)
         if (No > 1) then
            do t = 2, No
               temp_toks(:, t) = partition(temp_toks(3, t - 1), sep_)
            end do
         end if

         if (temp_toks(1, 1) /= '' .and. temp_toks(3, No) /= '') then
            allocate (tokens(No + 1))
            do t = 1, No
               if (t == No) then
                  tokens(t) = temp_toks(1, t)
                  tokens(t + 1) = temp_toks(3, t)
               else
                  tokens(t) = temp_toks(1, t)
               end if
            end do
         elseif (temp_toks(1, 1) /= '') then
            allocate (tokens(No))
            do t = 1, No
               tokens(t) = temp_toks(1, t)
            end do
         elseif (temp_toks(3, No) /= '') then
            allocate (tokens(No))
            do t = 1, No - 1
               tokens(t) = temp_toks(1, t + 1)
            end do
            tokens(No) = temp_toks(3, No)
         else
            allocate (tokens(No - 1))
            do t = 2, No
               tokens(t - 1) = temp_toks(1, t)
            end do
         end if

      else
         allocate (tokens(1))
         tokens(1) = self
      end if

   end subroutine split

end module mod_strings_ext
